<?php

/**
 * Web Upload上传调用类
 */
namespace app\admin\controller;

use think\App;

class Webupload extends Common{

    // 1.文件上传路径
    private static $uploadDir = 'uploads' . DIRECTORY_SEPARATOR . 'webupload' . DIRECTORY_SEPARATOR . 'upload';
    // 2.文件上传临时路径
    private static $targetDir = 'uploads' . DIRECTORY_SEPARATOR . 'webupload' . DIRECTORY_SEPARATOR . 'upload_tmp';
    // 3.设置临时存储文件大小，当超过大小时，将先存储超出大小文件在临时目录
    private static $memoryThreshold = 1024 * 1024 * 30;
    // 4.设置最大文件上传值
    private static $maxFileSize = 1024 * 1024 * 2000;
    // 5.最大请求值
    private static $maxRequestSize = 1024 * 1024 * 2048;

    public function __construct(App $app)
    {
        parent::__construct($app);
        //self::$uploadDir = app()->getRootPath() . self::$uploadDir;
        //self::$targetDir = app()->getRootPath() . self::$targetDir;
    }

    public function _empty() {
        header("HTTP/1.0 404 Not Found");
    }

    /**
     * 上传图片
     */
    public function imgUpload($name = 'file'){

        $this->chunkUpload($name, 'image');

        //创建临时存储分片文件夹
        $targetDir = self::$targetDir . DIRECTORY_SEPARATOR . 'images';
        if(!file_exists($targetDir)){
            @mkdir($targetDir);
        }

        //修改文件名称
        $nameArr = explode('.', $name);
        $newName = time() . rand(100000, 999999) . '.' . end($nameArr);
        $filePath = $targetDir . DIRECTORY_SEPARATOR . $name;

        $chunks = $this->request->param("chunks") ? $this->request->param("chunks") : 1;
        $uploadPath = self::$uploadDir . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . $newName;

        //合并文件
        $done = true;
        for( $index = 0; $index < $chunks; $index++ ) {
            if ( !file_exists("{$filePath}_{$index}.part") ) {
                $done = false;
                break;
            }
        }
        if ( $done ) {
            if (!$out = @fopen($uploadPath, "wb")) {
                die('{"jsonrpc" : "2.0", "error" : {"code": 1021, "message": "Failed to open output stream."}, "id" : "id"}');
            }

            if ( flock($out, LOCK_EX) ) {
                for( $index = 0; $index < $chunks; $index++ ) {
                    if (!$in = @fopen("{$filePath}_{$index}.part", "rb")) {
                        break;
                    }

                    while ($buff = fread($in, 4096)) {
                        fwrite($out, $buff);
                    }

                    @fclose($in);
                    @unlink("{$filePath}_{$index}.part");
                }

                flock($out, LOCK_UN);
            }
            @fclose($out);

        }

        $response = array(
            'success'=> true,
            'name'   => $newName,
            'url'    => DIRECTORY_SEPARATOR . $uploadPath
        );

        return json($response);

    }

    /**
     * 上传文件
     */
    public function fileUpload(){

    }

    /**
     * 文件分片上传
     * @param string $name
     * @return array|bool
     */
    function chunkUpload($name = 'file', $type = 'file'){
        header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
        header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
        header("Cache-Control: no-store, no-cache, must-revalidate");
        header("Cache-Control: post-check=0, pre-check=0", false);
        header("Pragma: no-cache");

        if($type == 'image'){
            $md5 = 'images';
        }else{
            $md5 = 'files';
        }

        //创建临时存储分片文件夹
        $targetDir = self::$targetDir . DIRECTORY_SEPARATOR . $md5;
        if(!file_exists($targetDir)){
            @mkdir($targetDir, 0777, true);
        }

        $filePath = $targetDir . DIRECTORY_SEPARATOR . $name;

        // Chunking might be enabled
        $cleanupTargetDir = false; // Remove old files
        $maxFileAge = 5 * 3600;
        $chunk = $this->request->param('chunk', 0);


        // Remove old temp files
        if ($cleanupTargetDir) {
            if (!is_dir($targetDir) || !$dir = opendir($targetDir)) {
                die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory."}, "id" : "id"}');
            }

            while (($file = readdir($dir)) !== false) {
                $tmpfilePath = $targetDir . DIRECTORY_SEPARATOR . $file;

                // If temp file is current file proceed to the next
                if ($tmpfilePath == "{$filePath}_{$chunk}.part" || $tmpfilePath == "{$filePath}_{$chunk}.parttmp") {
                    continue;
                }

                // Remove temp file if it is older than the max age and is not the current file
                if (preg_match('/\.(part|parttmp)$/', $file) && (@filemtime($tmpfilePath) < time() - $maxFileAge)) {
                    @unlink($tmpfilePath);
                }
            }
            closedir($dir);
        }

        // 打开并写入缓存文件
        if (!$out = @fopen("{$filePath}_{$chunk}.parttmp", "wb")) {
            die('{"jsonrpc" : "2.0", "error" : {"code": 1020, "message": "Failed to open output stream."}, "id" : "id"}');
        }

        if (!empty($_FILES)) {
            if ($_FILES["file"]["error"] || !is_uploaded_file($_FILES["file"]["tmp_name"])) {
                die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file."}, "id" : "id"}');
            }

            // Read binary input stream and append it to temp file
            if (!$in = @fopen($_FILES["file"]["tmp_name"], "rb")) {
                die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
            }
        } else {
            if (!$in = @fopen("php://input", "rb")) {
                die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
            }
        }

        while ($buff = fread($in, 4096)) {
            fwrite($out, $buff);
        }

        @fclose($out);
        @fclose($in);

        rename("{$filePath}_{$chunk}.parttmp", "{$filePath}_{$chunk}.part");


        //print_r($object_info);exit;
        //保存文件的顺序很重要!
//        $object = $object_info->rule('uniqid')->move(self::$targetDir . DIRECTORY_SEPARATOR . $md5 . DIRECTORY_SEPARATOR, I('chunk'));
//        if($object)
//        {
//            return ['chunks'=>I('chunks'),'chunk'=>I('chunk')];
//        }else{
//            return false;
//        }

    }

    /**
     * 全部分片上传完成后合并文件
     */
    public function batchUpload(){

        //$md5 = I('fileMd5');
        $md5 = 'files';
        $fileName = $this->request->param('fileName');

        $nameArr = explode('.', $fileName);
        $newFileName = time() . rand(100000, 999999) . '.' . end($nameArr);

        $dir = self::$targetDir . DIRECTORY_SEPARATOR . $md5;//echo $dir;

        if(is_dir($dir)) {
            //获取文件的顺序很重要!!!
            $files = array();
            $chunk_id = 0;
            $chunk_file = $dir . DIRECTORY_SEPARATOR . $fileName;

            while (file_exists($chunk_file . '_' . $chunk_id . '.part')){
                $files[] = $chunk_file . '_' . $chunk_id . '.part';
                $chunk_id++;
            }

            $path_file = $md5 . DIRECTORY_SEPARATOR . date('Ymd') . DIRECTORY_SEPARATOR . $newFileName;
            //日期目录不存在则创建目录
            if(!is_dir(self::$uploadDir . DIRECTORY_SEPARATOR . $md5 . DIRECTORY_SEPARATOR . date('Ymd')))
            {
                mkdir(self::$uploadDir . DIRECTORY_SEPARATOR . $md5 . DIRECTORY_SEPARATOR . date('Ymd'), 0777, true);
            }
            $count = 0;
            foreach ($files as $v)
            {
                $_file = file_get_contents($v);
                $_res = file_put_contents(self::$uploadDir . DIRECTORY_SEPARATOR . $path_file,$_file,FILE_APPEND);
                if($_res)
                {
                    unlink($v);
                }else{
                    $count++;
                }
            }
//            if($count == 0)
//            {
//                rmdir($dir);
//                //检查合并后的文件hash
//                $_hash = hash_file('sha1', PATH_FILE . $path_file);
//                //合并后的文件已存在则删除已合并文件并返回已有文件信息
//                $file_info = $this->modelFile->getInfo(['sha1'=>$_hash],'id,name,path,sha1,guid,md5');
//                if(!empty($file_info))
//                {
//                    unlink(PATH_FILE . $path_file);
//                    return $file_info;
//                }
//                //合并后的文件入库并返回
//                $_data = ['name' => $file_name, 'path' => $path_file, 'sha1' => $_hash,'guid'=>'','md5'=>request()->param()['md5']];
//                $result = $this->modelFile->addInfo($_data);
//                $_data['id'] = $result;
//                return $_data;
//            }else{
//                $this->error = '合并文件失败';
//                return false;
//            }
            $response = array(
                'success'=> true,
                'name'   => $newFileName,
                'url'    => DIRECTORY_SEPARATOR . self::$uploadDir . DIRECTORY_SEPARATOR . $path_file
            );

            return json($response);
        }else{
            echo '分片目录不存在!';
            return false;
        }

    }

    /**
     * 验证文件是否存在
     */
    public function md5check(){

    }

    /**
     * 分片验证，判断该分片是否已存在
     * @return bool
     */
    function checkChunk(){

        $md5 = $this->request->param('fileMd5');
        $chunk = $this->request->param('chunk');
        $fileName = $this->request->param('fileName');
        $dir = self::$targetDir . DIRECTORY_SEPARATOR . $md5;
        $chunkSize = $this->request->param('chunkSize');

        //$errorReturn = ['result'=>'fail', 'ifExist'=>fasle];
echo self::$targetDir;
        if(is_dir($dir)) {
            $files = $this->getFileByPath($dir);

            //判断当前分块是否存在
            $targetFileName = $fileName . '_' . $chunk . '.part';

            //判断该分片文件是否存在
            if(!in_array($targetFileName, $files))  return json(['result'=>'fail', 'ifExist'=>0]);

            //判断分片文件大小是否与前端设置分块大小一致
            if(filesize($dir . DIRECTORY_SEPARATOR . $targetFileName) != $chunkSize)  return json(['result'=>'fail', 'ifExist'=>0]);

            return json(array('result'=>'success', 'ifExist'=>'ok'));
        }else{
            return json(['result'=>'fail', 'ifExist'=>0]);
        }

    }

    /**
     * 根据文件夹获取该文件夹下全部文件
     * @param $dir
     */
    public function getFileByPath($dir){

        //$dir = self::$uploadDir;
        if(!is_dir($dir))  return false;

        $file_arr = array();

        //打开
        if($dh = @opendir($dir)){
            //读取
            while(($file = readdir($dh)) !== false){
                if($file != '.' && $file != '..'){
                    $file_arr[] = $file;
                }
            }
            //关闭
            closedir($dh);
        }

        return $file_arr;
    }

}